package com.kjlink.widget.monitoring.aspect;

import com.kjlink.widget.monitoring.annotation.MonitoringEventReport;
import com.kjlink.widget.monitoring.model.MonitorDataModel;
import com.kjlink.widget.monitoring.report.MonitorEventReportFacade;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.lang.reflect.Method;
import java.lang.reflect.Parameter;

/**
 * 描述:
 * 事件上报切面
 *
 * @author Vic.xu
 * @since 2025-08-21 14:00
 */
@Aspect
public class MonitorEventReportAspect {

    private int maxExceptionMessageLength = 512;

    private static final Logger LOGGER = LoggerFactory.getLogger(MonitorEventReportAspect.class);

    private static final SpelExpressionParser SPEL_PARSER = new SpelExpressionParser();

    private MonitorEventReportFacade monitorEventReportFacade;

    public MonitorEventReportAspect(MonitorEventReportFacade monitorEventReportFacade) {
        this.monitorEventReportFacade = monitorEventReportFacade;
    }

    public void setMaxExceptionMessageLength(int maxExceptionMessageLength) {
        // 断言 maxExceptionMessageLength > 4
        Assert.isTrue(maxExceptionMessageLength > 4, "maxExceptionMessageLength must be greater than 4");
        this.maxExceptionMessageLength = maxExceptionMessageLength;
    }

    @Pointcut("@annotation(com.kjlink.widget.monitoring.annotation.MonitoringEventReport)")
    public void pointcut() {
    }

    @AfterThrowing(pointcut = "pointcut()", throwing = "ex")
    public void afterThrowing(JoinPoint joinPoint, Throwable ex) {
        try {


            // 获取方法签名
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            Method method = signature.getMethod();

            // 获取自定义注解
            MonitoringEventReport eventReportAnnotation = method.getAnnotation(MonitoringEventReport.class);
            if (!eventReportAnnotation.enable()) {
                return;
            }
            MonitorDataModel model = new MonitorDataModel();
            model.setEventType(eventReportAnnotation.eventType());
            model.setMonitorType(eventReportAnnotation.monitorType());
            String businessId = getBusinessId(joinPoint, method, eventReportAnnotation);
            model.setBusinessId(businessId);
            model.setBusinessType(eventReportAnnotation.businessType());
            // exception
            model.setException(
                    org.apache.commons.lang3.StringUtils.abbreviate(ex.getMessage(), maxExceptionMessageLength));
            String eventCode = ex.getClass().getName();
            model.setEventCode(eventCode);
            monitorEventReportFacade.fillDataAndSend(model);
        } catch (Exception e) {
            LOGGER.error("MonitorEventReportAspect afterThrowing error", e);
        }
    }


    private String getBusinessId(JoinPoint joinPoint, Method method, MonitoringEventReport monitoringEventReport) {
        String businessIdParameterExpress = monitoringEventReport.businessIdParamExpress();
        if (!StringUtils.hasText(businessIdParameterExpress)) {
            return null;
        }
        Parameter[] parameters = method.getParameters();
        if (ObjectUtils.isEmpty(parameters)) {
            return null;
        }
        //将方法的参数名和参数值一一对应的放入上下文中
        EvaluationContext ctx = new StandardEvaluationContext();
        Object[] arguments = joinPoint.getArgs();
        for (int i = 0; i < parameters.length; i++) {
            String name = parameters[i].getName();
            Object argument = arguments[i];
            ctx.setVariable(name, argument);
        }
        try {
            Object businessId = SPEL_PARSER.parseExpression(businessIdParameterExpress).getValue(ctx);
            if (businessId != null) {
                return String.valueOf(businessId);
            }
            return null;
        } catch (Exception e) {
            LOGGER.error("businessIdParameterExpress error:{}", e);
            return null;
        }
    }

    public static void main(String[] args) {
        String s = "!22";
        String abbreviate = org.apache.commons.lang3.StringUtils.abbreviate(s, 4);
        System.out.println(abbreviate);
    }

}
